package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.tianji.learning.utils.LearningRecordDelayTaskHandel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor
@Lazy
@SuppressWarnings("ALL")
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    private final ILearningLessonService learningLessonService;
    private final CourseClient courseClient;
    private final LearningRecordDelayTaskHandel taskHandel;
    private final RabbitMqHelper mqHelper;

    /**
     * 查询指定课程的学习记录
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        // 1.获取登录用户
        Long userId = UserContext.getUser();
        // 2.查询课表
        LearningLesson lesson = learningLessonService.queryByUserAndCourseId(userId, courseId);
        // 3.查询学习记录
        // select * from xx where lesson_id = #{lessonId}
        List<LearningRecord> records = lambdaQuery()
                .eq(LearningRecord::getLessonId, lesson.getId()).list();
        // 4.封装结果
        LearningLessonDTO dto = new LearningLessonDTO();
        dto.setId(lesson.getId());
        dto.setLatestSectionId(lesson.getLatestSectionId());
        dto.setRecords(BeanUtils.copyList(records, LearningRecordDTO.class));
        return dto;
    }

    /**
     * 提交学习记录
     *
     * @param learningRecordDTO
     */
    @Override
    @Transactional
    public void postLearningRecord(LearningRecordFormDTO learningRecordFormDTO) {
        Long userId = UserContext.getUser();
        Boolean finished = false;
        //1.判断类型 是考试还是视频
        if (learningRecordFormDTO.getSectionType() == SectionType.EXAM) {
            //2.1 考试 则提交即视为完成 新增学习记录

            // 考试提交即视为完成 更改finished状态
            finished = true;

            // 新增学习记录数据
            LearningRecord learningRecord = new LearningRecord();
            learningRecord.setUserId(userId);
            learningRecord.setFinished(true);
            learningRecord.setCreateTime(learningRecordFormDTO.getCommitTime());
            learningRecord.setFinishTime(learningRecordFormDTO.getCommitTime());
            learningRecord.setLessonId(learningRecordFormDTO.getLessonId());
            learningRecord.setSectionId(learningRecordFormDTO.getSectionId());
            boolean save = save(learningRecord);
            if (!save) {
                throw new DbException("新增学习记录失败");
            }
        }

        //2.2 视频 判断有没有超过50% 新增学习记录

        // 获得学习记录的小结信息 可能为空
        LearningRecord learningRecord = oldRecord(learningRecordFormDTO.getLessonId(), learningRecordFormDTO.getSectionId());
        // 视频可以重复学习 判断小节是否完成  如果小节已完成或者没到50%则不用管交给延迟任务处理


        /*if (learningRecord != null && learningRecord.getFinished() == true) {
            learningRecord.setMoment(learningRecordFormDTO.getMoment());
            learningRecord.setUpdateTime(learningRecordFormDTO.getCommitTime());

            // 更新学习记录
            boolean success = updateById(learningRecord);
            if (!success) {
                throw new DbException("更新学习记录失败");
            }
        }*/


        // 判断学习记录是否为空
        if (learningRecord == null) {
            // 添加createTime
            learningRecord.setCreateTime(learningRecordFormDTO.getCommitTime());
        }

        //判断有没有超过50%
        if (learningRecordFormDTO.getMoment() * 2 >= learningRecordFormDTO.getDuration()) {
            // 大于50% 更改小结状态为学完
            learningRecord.setFinished(true);
            // 更新 finished状态
            finished = true;
            // 添加学习完成时间
            learningRecord.setFinishTime(learningRecordFormDTO.getCommitTime());
        }
       /* // 没有到50%
        learningRecord.setMoment(learningRecord.getMoment());
        learningRecord.setUpdateTime(learningRecordFormDTO.getCommitTime());
        // 新增或更新
        boolean success = saveOrUpdate(learningRecord);
        if (!success){
            throw new DbException("学习记录提交失败");
        }*/

        //3.1 更新课表
        Boolean aBoolean = updateLearningLesson(learningRecordFormDTO, finished);
        if (!aBoolean) {
            throw new DbException("课表更新失败");
        }

        //4.发送Mq异步通知  考完一场试或看完一个视频即视为完成一小节学习内容 +10 上限50
        mqHelper.send(MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.LEARN_SECTION,
                userId);

    }

    /**
     * 查询redis中有没有数据 没有再去数据库查 提交学习记录
     *
     * @param lessonId
     * @param sectionId
     * @return
     */
    private LearningRecord oldRecord(Long lessonId, Long sectionId) {
        // 查询redis中有没有数据
        LearningRecord learningRecord = taskHandel.readRecordCache(lessonId, sectionId);
        // 有 则返回
        if (learningRecord != null) {
            return learningRecord;
        }
        // 没有则再从数据库查  再写入redis 再返回
        learningRecord = lambdaQuery()
                .eq(LearningRecord::getLessonId, learningRecord)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
        taskHandel.writeLearningRecord(learningRecord);
        return learningRecord;
    }

    /**
     * 更改课表信息
     *
     * @param learningRecordFormDTO
     * @param finished
     * @return
     */
    private Boolean updateLearningLesson(LearningRecordFormDTO learningRecordFormDTO, Boolean finished) {
        // 获得原始课表信息  创建LearningLesson对象
        LearningLesson lesson = learningLessonService.getById(learningRecordFormDTO.getLessonId());

        if (lesson == null) {
            throw new DbException("课表信息不存在");
        }
        lesson.setLatestLearnTime(learningRecordFormDTO.getCommitTime());
        lesson.setUpdateTime(learningRecordFormDTO.getCommitTime());
        lesson.setLatestSectionId(learningRecordFormDTO.getSectionId());
        // 如果新完成了一个小结 则完成总小结数量+1， 判断已学习小节数==总小节数
        if (finished) {
            lesson.setLearnedSections(lesson.getLearnedSections() + 1);

            // 获得课程总小结数量
            CourseFullInfoDTO courseInfoById = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
            if (courseInfoById != null) {
                log.error("课程信息不存在");
                return false;
            }
            Integer num = courseInfoById.getSectionNum();
            // 判断已学习小节数==总小节数？ 更改状态
            if (lesson.getLearnedSections() == num) {
                lesson.setStatus(LessonStatus.FINISHED);
            }
        }

        // 更新课表
        return learningLessonService.updateById(lesson);
    }
}
